09Socket通信中,为什么要关闭连接(`close()`方法)?
问题: Socket 通信中,为什么要关闭连接(close()方法)?
👇 点击展开/折叠 面试背诵模板(建议先背这个)
资源释放:文件描述符与内核缓冲区
在 Unix/Linux 中,Socket 遵循“一切皆文件”哲学,打开后占用一个非负整数(文件描述符)。每个进程的 FD 数量受系统限制(ulimit -n),若不调用 close(),FD 无法归还给内核,最终导致新连接无法创建。同时,内核为该连接分配的发送/接收缓冲区(数十 KB 至数 MB)也无法释放,长期累积将导致内存资源枯竭。
1 | # 危险代码:未关闭会导致 FD 泄漏 |
网络协议:触发 TCP 四次挥手
close() 的底层行为是向对端发送 FIN 包,启动四次挥手流程,使双方有序释放连接状态。若不调用 close(),服务端 recv() 永远收不到 b''(EOF),将一直挂起等待数据;客户端的连接也会被内核(或 NAT/防火墙)视为“僵尸连接”,占用端口和会话表项。对于服务端,accept() 返回的每个客户端套接字若不关闭,会导致大量 CLOSE_WAIT 堆积,最终耗尽端口资源。
危险场景与最佳实践
陷阱:代码抛出异常时,若 close() 写在 try 末尾,会被跳过执行。解决方案:使用 try-finally 或 with 上下文管理器(Python 3.3+ 支持 Socket 上下文协议)。
1 | # 方案一:try-finally(兼容所有版本) |
注意:即使服务端调用了 close(),操作系统内核会进入 TIME_WAIT 状态(默认持续 2MSL,约 60 秒),确保所有延迟数据包被丢弃。若需立即重启服务,可设置 SO_REUSEADDR 选项允许端口复用,但这并不能替代 close() 本身的资源释放职责。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 LGQ的博客!